home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / oper_sys / quartz / quartz10.lha / src / runtime / processor.c < prev    next >
C/C++ Source or Header  |  1990-05-18  |  7KB  |  383 lines

  1. /* Central grubby thread package routines: deal with operating environment
  2.  * -- don't compile with -pg */ 
  3.  
  4. #include <stdio.h>
  5. #include <signal.h>
  6. #include <parallel/microtask.h>
  7. #include "thread.h"
  8. #include "synch.h"
  9. #include <usclkc.h>
  10. #include "quartzcommon.h"
  11. #include "profile.h"
  12. #include "internal.h"
  13.  
  14. /* imported */
  15. int exit();
  16. void shminit();
  17. char *shsbrk();
  18.  
  19. /* exported out of package */
  20. shared int numProcessors = 1;
  21.  
  22. /* exported within package */
  23. private PrivateProcessor pP = {0,0,0,0,0,0};
  24. shared int processGroup;
  25. shared int affinity = FALSE;
  26.  
  27. void IdleLoop(), Dummy(), KillAll(), Done(), ProcessorInit();
  28.  
  29. /* local to this file */
  30.  
  31. #ifndef PRESTO
  32. static shared ReadyQ readyList[NUMPROCS];
  33. static shared int numQueues = 1;
  34. static shared ReadyQ *firstQ, *lastQ;
  35. static shared usclk_t beginTime;
  36. static shared usclk_t endTime;
  37.  
  38. void Startup(), ReadyqInit();
  39.  
  40. /* Note: it's simplest just to start everybody, make sure pP.thread
  41.  * is initialized, and then to start profiling */
  42. main (argc, argv)
  43.     int argc;
  44.     char **argv;
  45.     {
  46.     char **p = argv + 1;
  47. #ifdef PROFILE
  48.     int numProfilers = 1;
  49. #endif
  50.  
  51.     usclk_init();
  52.     ProcessorInit(0);
  53.     beginTime = GETUSCLK();
  54.     for (; *p && **p == '-'; p++)
  55.         switch (*(*p + 1))
  56.             {
  57. #ifdef PROFILE
  58.             case 'p':
  59.                 numProfilers = atoi(*p + 2);
  60.                 break;
  61. #endif
  62.             case 'n':
  63.                 numQueues = numProcessors = atoi(*p + 2);
  64.                 break;
  65.             case 'a':
  66.                 affinity = TRUE;
  67.                 break;
  68.             }
  69.     if (numProcessors <= 0)
  70.         {
  71.         printf("Too few processors: %d\n", numProcessors);
  72.         exit(1);
  73.         }
  74. #ifdef PROFILE
  75.     if ((numProcessors+numProfilers) > NUMPROCS || numProfilers > MaxProfilers)
  76.         {
  77.         printf("Too many processors: %d %d\n", numProcessors, numProfilers);
  78.         exit(1);
  79.         }
  80.     ProcessorListInit();
  81.     ProfileInit(numProfilers);
  82.     MFork(ProfileStart, numProcessors, numProcessors + numProfilers, FALSE);
  83. #else
  84.     if (numProcessors > NUMPROCS) 
  85.         {
  86.         printf("Too many processors: %d\n", numProcessors);
  87.         exit(1);
  88.         }
  89. #endif
  90.     PrivProcessorInit(0);
  91.     shminit();
  92.     StackpoolInit();
  93.     ThreadpoolInit();
  94.     ReadyqInit();
  95.  
  96.     processGroup = getpgrp(0);
  97.     (void)ThreadStart(Main, NOJOIN, (char *)NULL, 2, argc, argv);
  98.  
  99. #ifdef PROFILE
  100.     ProfileSetAllBusy(numProcessors);
  101. #endif
  102.  
  103.     MFork(Startup, 1, numProcessors, TRUE);
  104. /* PROBLEM: Can't call Startup directly here, since with
  105.  * optimizing on, it gets in-lined, and you lose bigtime */
  106.     }
  107.  
  108. void Startup (id)
  109.     {
  110.     fflush(stdout);
  111.     if (id != 0)
  112.         {
  113.         ProcessorInit(id);
  114.         PrivProcessorInit(id);
  115.         }
  116. #ifdef PROFILE
  117.     ReplaceOnIdStack(IdleID, BusyState);
  118.     SetProfileOn();
  119. #endif
  120.     INIT();
  121.     IdleLoop(0);
  122.     }
  123.  
  124. #define NextQ(q)    ((q == lastQ) ? firstQ : (q + 1))
  125.  
  126. /* If finishing, then we enter with pP.thread == the finishing thread,
  127.  * if not, we enter with pP.thread = pP.idleThread
  128.  */
  129. void IdleLoop (finishing) 
  130.     int finishing;
  131.     {
  132.     register Thread *t;
  133.     Stack *s;
  134.     register ReadyQ *q;
  135.     register int *bottom;
  136.     int *argv;
  137.     int i;
  138.     int *newfp;
  139.  
  140.     if (finishing)
  141.         {
  142.         t = pP.thread;
  143.         s = t->stack;
  144.         if (t->join.status == NOJOIN)
  145.             { ThreadFree(t); }
  146.         else /* you might think that we could just look at waiter, and resume
  147.              * if it is set -- but we must also be sure it has finished
  148.              * crawling off the stack */
  149.             {
  150.             SLNPAcquire(&t->join.lock);
  151.             if (t->join.status == CALLER_READY)
  152.                 {  /* no need to release the lock -- just resume */
  153.                 pP.thread = t->join.waiter;
  154. #ifdef PROFILE
  155.                 pP.proc->curThread = pP.thread;
  156. #endif
  157.                 StackpoolPut(s);
  158.                 ThreadFree(t);
  159.                 t = pP.thread;
  160.                 RESUME(t);
  161.                 }
  162.             else
  163.                 {
  164. #ifdef PROFILE
  165.                 SetStateBlocked();
  166.                 if (t->p)
  167.                     t->p->number[0]++;
  168. #endif
  169.                 t->join.status = CALLEE_DONE;
  170.                 SLNPRelease(&t->join.lock);
  171.                 }
  172.             }
  173.         }
  174. #ifdef PROFILE             /* here's where we start spinning */
  175.     pP.proc->curThread = pP.thread = pP.idleThread; 
  176.     NowIdle();
  177.     DecNominal();
  178.     AtomicIncrP(&(pP.lastLook->empty->number[0]));
  179.                 /* So we'll see these as called from Idle Loop */
  180.     PushOnIdStack(pP.lastLook->empty, (unsigned int)SpinState);
  181.     PopOffIdStack();
  182.     PushOnIdStack(pP.lastLook->lock.p, (unsigned int)SpinState);
  183.     for (q = pP.lastLook;; q = NextQ(q))
  184.         {
  185.         ReplaceOnIdStack(pP.lastLook->empty, SpinState);
  186.         if (q->started)
  187.             {
  188.             ReplaceOnIdStack(q->lock.p, SpinState);
  189.             if (SLNPTestAndGet(&q->lock)) 
  190.                 {
  191.                 SetStateBusy();
  192.                 if (t = q->started)
  193.                     break;
  194.                 else 
  195.                     SLNPRelease(&(q->lock));
  196.                 }
  197.             }
  198.         }
  199.     q->started = t->next;
  200.     SLNPRelease(&(q->lock));
  201.     PopOffIdStack();
  202.     AtomicDecrP(&(pP.lastLook->empty->number[0]));
  203.     NowBusy();         /* here's where we stop spinning */
  204.     pP.proc->curThread = t;    
  205.     pP.thread = t;
  206.     SetStateBusy();
  207. #else
  208.     for (q = pP.lastLook;; q = NextQ(q))
  209.         {
  210.         if (q->started && SpinLockTestAndGet(&q->lock)) 
  211.             {
  212.             if (t = q->started)
  213.                 break;
  214.             else 
  215.                 SpinLockRelease(&(q->lock));
  216.             }
  217.         }
  218.     q->started = t->next;
  219.     SpinLockRelease(&(q->lock));
  220.     pP.thread = t;
  221. #endif
  222.  
  223.     if (t->stack)
  224.         {
  225.         if (finishing)
  226.             StackpoolPut(s);
  227.         RESUME(t);
  228.         }
  229.     else
  230.         {
  231.         if (!finishing)
  232.             s = StackpoolGet();
  233.         t->stack = s;
  234.         bottom = &(s->space[StackSize]);
  235. #ifdef PROFILE
  236.             /* probably only needed when PARANOID */
  237.         DUMMYFRAME(bottom);        /* decrements bottom */
  238.         newfp = bottom;
  239. #endif
  240.         argv = t->arglist;
  241.         for (i = t->numargs; i > 0; i--)
  242.             *--bottom = *argv++;
  243.  
  244.         STARTUP(t, bottom, newfp);
  245.         THREAD_EXIT();
  246.         }
  247.     }
  248.  
  249. void ProgramDone ()
  250.     {
  251.     endTime = GETUSCLK();
  252.     printf("Time: %f\n", ((float)(endTime - beginTime)) / 1000000);
  253. #ifdef PROFILE
  254.     ProfileFinish();
  255. #else
  256.     if (numProcessors > 1)
  257.         KillAll();
  258.     exit(0);
  259. #endif
  260.     }
  261.  
  262. void ReadyqInit ()
  263.      {
  264.     int i;
  265.  
  266.     for (i = 0; i < numQueues; i++)
  267.         {
  268.         readyList[i].started = NULL;
  269.         SpinLockInit(&readyList[i].lock, "readyQ[i].lock");
  270. #ifdef PROFILE
  271.         readyList[i].empty = SynchInit("readyQ[i].empty", VarSpinDependency);
  272. #endif
  273.         }
  274.     firstQ = &readyList[0];
  275.     lastQ = &readyList[numQueues - 1];
  276.     }
  277.  
  278. #endif /* ifndef PRESTO */
  279.  
  280. #ifdef PROFILE
  281. void ProfileStart (id)
  282.     {
  283.     ProcessorInit(id);
  284.     PrivProcessorInit(id);
  285.     ProfileExternal();
  286.     }
  287. #endif
  288.  
  289. void KillAll ()
  290.     {
  291.     (void)signal(SIGUSR1, Dummy);
  292.     (void)killpg(processGroup, SIGUSR1);
  293.     }
  294.  
  295. void PrivProcessorInit (id)
  296.     int id;
  297.     {
  298.     pP.myId = id;
  299.  
  300.     pP.seed = pP.myId;
  301. #ifndef PRESTO
  302.     pP.lastLook = pP.putQ = &readyList[pP.myId % numQueues];
  303. #endif
  304.  
  305.     pP.deadThreads = NULL;
  306.     pP.deadCount = 0;
  307.  
  308. #ifdef PROFILE
  309.     pP.freeSynch = NULL;
  310.     pP.proc = &(processorList[pP.myId]);
  311.     pP.thread = pP.idleThread = pP.proc->curThread;
  312. #endif
  313.     }
  314.  
  315. void ProcessorInit (id)
  316.     int id;
  317.     {
  318.     (void)signal(SIGUSR1, Done);
  319.     if (affinity && tmp_affinity(id) == -1)
  320.         fprintf(stderr, "Unable to affinity %d\n", id);
  321.     }
  322.  
  323. void TooSmall (n)
  324.     int n;
  325.     {
  326.     printf("Fatal Error: ThreadStart passed too many arguments %d\n", n);
  327.     fflush(stdout);
  328.     KillAll();
  329.     exit(1);
  330.     }
  331.  
  332. void Done ()
  333.     {
  334.     fflush(stdout);
  335.     fflush(stderr);
  336.     exit(0);
  337.     }
  338.  
  339. void MFork (func, lb, ub, self)
  340.   void (*func)();
  341.   int lb, ub;
  342.   int self;
  343.   {
  344.   int i;
  345.   int pid;
  346.  
  347.   for (i = lb; i < ub; i++)
  348.     {
  349.     pid = fork();
  350.     if (pid == 0)
  351.         func(i);
  352.     else if (pid == -1)
  353.         KillAll();
  354.     }
  355.   if (self)
  356.     func(0);
  357.   }
  358.  
  359. int getid ()
  360.     {
  361.     return(pP.myId);
  362.     }
  363.  
  364. char *myshmalloc (n) 
  365.     unsigned n;
  366.     {
  367.     char *p;
  368.     char *shmalloc();
  369.  
  370.     if ((p = shmalloc(n)) == NULL) 
  371.         {
  372.         fprintf(stderr, "Out of space\n");
  373.         fflush(stderr);
  374.         fflush(stdout);
  375.         KillAll();
  376.         exit(1);
  377.         }
  378.     return(p);
  379.     }
  380.  
  381. void Dummy ()
  382.     {}
  383.